From d49020eed746315183168f58e9fa6b8059231e8e Mon Sep 17 00:00:00 2001 From: "kfraser@localhost.localdomain" Date: Wed, 10 Jan 2007 16:17:35 +0000 Subject: [PATCH] [HVM][VMX] Fix problem taking an NMI on entry/exit to/from VMX mode. Also cleans up code a bit. Signed-off-by: Keir Fraser --- xen/arch/x86/hvm/vmx/vmcs.c | 9 ++++++++- xen/arch/x86/hvm/vmx/x86_32/exits.S | 31 +---------------------------- xen/arch/x86/hvm/vmx/x86_64/exits.S | 27 +------------------------ xen/arch/x86/oprofile/nmi_int.c | 2 +- xen/arch/x86/traps.c | 2 +- 5 files changed, 12 insertions(+), 59 deletions(-) diff --git a/xen/arch/x86/hvm/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c index 8355c6e54d..dde3a4c201 100644 --- a/xen/arch/x86/hvm/vmx/vmcs.c +++ b/xen/arch/x86/hvm/vmx/vmcs.c @@ -278,7 +278,14 @@ static void vmx_set_host_env(struct vcpu *v) host_env.tr_base = (unsigned long) &init_tss[cpu]; __vmwrite(HOST_TR_SELECTOR, host_env.tr_selector); __vmwrite(HOST_TR_BASE, host_env.tr_base); - __vmwrite(HOST_RSP, (unsigned long)get_stack_bottom()); + + /* + * Skip end of cpu_user_regs when entering the hypervisor because the + * CPU does not save context onto the stack. SS,RSP,CS,RIP,RFLAGS,etc + * all get saved into the VMCS instead. + */ + __vmwrite(HOST_RSP, + (unsigned long)&get_cpu_info()->guest_cpu_user_regs.error_code); } static void construct_vmcs(struct vcpu *v) diff --git a/xen/arch/x86/hvm/vmx/x86_32/exits.S b/xen/arch/x86/hvm/vmx/x86_32/exits.S index 144dd174d4..35b67d3c48 100644 --- a/xen/arch/x86/hvm/vmx/x86_32/exits.S +++ b/xen/arch/x86/hvm/vmx/x86_32/exits.S @@ -29,35 +29,7 @@ andl $~3,reg; \ movl (reg),reg; -/* - * At VMExit time the processor saves the guest selectors, esp, eip, - * and eflags. Therefore we don't save them, but simply decrement - * the kernel stack pointer to make it consistent with the stack frame - * at usual interruption time. The eflags of the host is not saved by VMX, - * and we set it to the fixed value. - * - * We also need the room, especially because orig_eax field is used - * by do_IRQ(). Compared the cpu_user_regs, we skip pushing for the following: - * (10) u32 gs; - * (9) u32 fs; - * (8) u32 ds; - * (7) u32 es; - * <- get_stack_bottom() (= HOST_ESP) - * (6) u32 ss; - * (5) u32 esp; - * (4) u32 eflags; - * (3) u32 cs; - * (2) u32 eip; - * (2/1) u16 entry_vector; - * (1/1) u16 error_code; - * However, get_stack_bottom() actually returns 20 bytes before the real - * bottom of the stack to allow space for: - * domain pointer, DS, ES, FS, GS. Therefore, we effectively skip 6 registers. - */ - -#define NR_SKIPPED_REGS 6 /* See the above explanation */ #define HVM_SAVE_ALL_NOSEGREGS \ - subl $(NR_SKIPPED_REGS*4), %esp; \ movl $0, 0xc(%esp); /* XXX why do we need to force eflags==0 ?? */ \ pushl %eax; \ pushl %ebp; \ @@ -74,8 +46,7 @@ popl %esi; \ popl %edi; \ popl %ebp; \ - popl %eax; \ - addl $(NR_SKIPPED_REGS*4), %esp + popl %eax ALIGN ENTRY(vmx_asm_vmexit_handler) diff --git a/xen/arch/x86/hvm/vmx/x86_64/exits.S b/xen/arch/x86/hvm/vmx/x86_64/exits.S index d427ac2cd5..cbe9902391 100644 --- a/xen/arch/x86/hvm/vmx/x86_64/exits.S +++ b/xen/arch/x86/hvm/vmx/x86_64/exits.S @@ -29,31 +29,7 @@ andq $~7,reg; \ movq (reg),reg; -/* - * At VMExit time the processor saves the guest selectors, rsp, rip, - * and rflags. Therefore we don't save them, but simply decrement - * the kernel stack pointer to make it consistent with the stack frame - * at usual interruption time. The rflags of the host is not saved by VMX, - * and we set it to the fixed value. - * - * We also need the room, especially because orig_eax field is used - * by do_IRQ(). Compared the cpu_user_regs, we skip pushing for the following: - * (10) u64 gs; - * (9) u64 fs; - * (8) u64 ds; - * (7) u64 es; - * <- get_stack_bottom() (= HOST_ESP) - * (6) u64 ss; - * (5) u64 rsp; - * (4) u64 rflags; - * (3) u64 cs; - * (2) u64 rip; - * (2/1) u32 entry_vector; - * (1/1) u32 error_code; - */ -#define NR_SKIPPED_REGS 6 /* See the above explanation */ #define HVM_SAVE_ALL_NOSEGREGS \ - subq $(NR_SKIPPED_REGS*8), %rsp; \ pushq %rdi; \ pushq %rsi; \ pushq %rdx; \ @@ -85,8 +61,7 @@ popq %rcx; \ popq %rdx; \ popq %rsi; \ - popq %rdi; \ - addq $(NR_SKIPPED_REGS*8), %rsp; + popq %rdi ALIGN ENTRY(vmx_asm_vmexit_handler) diff --git a/xen/arch/x86/oprofile/nmi_int.c b/xen/arch/x86/oprofile/nmi_int.c index 15e2818edb..ffefe3bf2d 100644 --- a/xen/arch/x86/oprofile/nmi_int.c +++ b/xen/arch/x86/oprofile/nmi_int.c @@ -42,7 +42,7 @@ extern int is_profiled(struct domain *d); extern size_t strlcpy(char *dest, const char *src, size_t size); -int nmi_callback(struct cpu_user_regs *regs, int cpu) +static int nmi_callback(struct cpu_user_regs *regs, int cpu) { int xen_mode, ovf; diff --git a/xen/arch/x86/traps.c b/xen/arch/x86/traps.c index cf1defeae3..e8ff825ea7 100644 --- a/xen/arch/x86/traps.c +++ b/xen/arch/x86/traps.c @@ -1854,7 +1854,7 @@ static int dummy_nmi_callback(struct cpu_user_regs *regs, int cpu) } static nmi_callback_t nmi_callback = dummy_nmi_callback; - + asmlinkage void do_nmi(struct cpu_user_regs *regs) { unsigned int cpu = smp_processor_id(); -- 2.30.2